#include <ani.h>
#include <array>
#include <iostream>
void createInstance(ani_env* env,ani_class* cls, ani_object* person_obj){
    //这里只能创建一个 Class 的实例，可以尝试改为 ani_interface/Person 会无法创建Object
    static const char *className = "ani_property.PersonInner";
    if (ANI_OK != env->FindClass(className, cls)) {
        std::cerr << "Not found '" << className << "'" << std::endl;
        return;
    }

    ani_method ctor;
    if (ANI_OK != env->Class_FindMethod(*cls, "<ctor>", nullptr, &ctor)){
        std::cerr << "get ctor Failed'" << className << "'" << std::endl;
        return;
    }

    if (ANI_OK != env->Object_New(*cls, ctor, person_obj)){
        std::cerr << "Create Object Failed'" << className << "'" << std::endl;
        return;
    }
}

static ani_object createPerson([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_object object){
    static const char *className = "ani_property.PersonInner";
    ani_object person_obj = {};
    ani_class cls;
    createInstance(env, &cls, &person_obj);

    //从C++的string (大多数情况是UTF8) 构造一个 ani_string
    std::string name = "Goose";
    ani_string name_string{};
    env->String_NewUTF8(name.c_str(), name.size(), &name_string);
    ani_int age_value(42);

    // Interface 及实现 Interface 中的成员都是 Property而不是 Field (参考spec, Interface Properties)
    {
        // 实现方案1：
        env->Object_SetPropertyByName_Int(person_obj, "age", age_value);
        //调用 set name(n:string)
        env->Object_SetPropertyByName_Ref(person_obj, "name", name_string);

        ani_int age_value_ret;
        ani_ref name_string_ret;
        env->Object_GetPropertyByName_Int(person_obj, "age", &age_value_ret);
        std::cout<< "see: "<< age_value_ret << std::endl;
        env->Object_GetPropertyByName_Ref(person_obj, "name", &name_string_ret);
    }
    // {
    //     // 实现方案2：
    //     ani_method ageSetter;
    //     if(ANI_OK != env->Class_FindSetter(cls, "age",  &ageSetter)){
    //         std::cerr << "Class_FindMethod Fail'" << className << "'" << std::endl;
    //     }

    //     if(ANI_OK != env->Object_CallMethod_Void(person_obj, ageSetter, age_value))
    //     {
    //         std::cerr << "Object_CallMethod_Void Fail'" << className << "'" << std::endl;
    //         return person_obj;
    //     }
        
    //     ani_method nameSetter;
    //     if(ANI_OK != env->Class_FindSetter(cls, "name", &nameSetter)){
    //         std::cerr << "Class_FindMethod Fail'" << "<set>name" << "'" << std::endl;
    //     }

    //     //调用 set name(n:string)
    //     if(ANI_OK != env->Object_CallMethod_Void(person_obj, nameSetter, name_string))
    //     {
    //         std::cerr << "Object_CallMethod_Void Fail'" << className << "'" << std::endl;
    //         return person_obj;
    //     }
    // }

    // {
    //     // 实现方案3：
    //     if(ANI_OK != env->Object_CallMethodByName_Void(person_obj, "<set>age", nullptr, age_value))
    //     {
    //         std::cerr << "Object_CallMethodByName_Void Fail'" << className << "'" << std::endl;
    //         return person_obj;
    //     }

    //     //调用 set name(n:string)
    //     if(ANI_OK != env->Object_CallMethodByName_Void(person_obj, "<set>name", nullptr, name_string))
    //     {
    //         std::cerr << "Object_CallMethodByName_Void Fail'" << className << "'" << std::endl;
    //         return person_obj;
    //     }
    // }
    return person_obj;
}

ani_int bindGet([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_object object){
    ani_int rs;
    const char* fieldName = "_thisIsProperty";
    env->Object_GetFieldByName_Int(object, fieldName, &rs);
    return rs;
}

void bindSet([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_object object, ani_int i){
    
    const char* fieldName = "_thisIsProperty";
    env->Object_SetFieldByName_Int(object, fieldName, i);
    return;
}


ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result)
{
    ani_env *env;
    if (ANI_OK != vm->GetEnv(ANI_VERSION_1, &env)) {
        std::cerr << "Unsupported ANI_VERSION_1" << std::endl;
        return ANI_ERROR;
    }

    static const char *className = "ani_property.PersonInner";
   
    ani_class cls;
    if (ANI_OK != env->FindClass(className, &cls)) {
        std::cerr << "Not found '" << className << "'" << std::endl;
        return ANI_ERROR;
    }

    std::array methods = {
        ani_native_function {"createPerson", nullptr, reinterpret_cast<void *>(createPerson)},
        ani_native_function {"thisIsPropertyGetter", nullptr, reinterpret_cast<void *>(bindGet)},
        ani_native_function {"thisIsPropertySetter", nullptr, reinterpret_cast<void *>(bindSet)},
    };

    std::cout << "Start bind native methods to '" << className << "'" << std::endl;

    if (ANI_OK != env->Class_BindNativeMethods(cls, methods.data(), methods.size())) {
        std::cerr << "Cannot bind native methods to '" << className << "'" << std::endl;
        return ANI_ERROR;
    };
    std::cout << "Finish bind native methods to '" << className << "'" << std::endl;

    {

    }

    *result = ANI_VERSION_1;
    return ANI_OK;
}